package com.asen.commons.core.base.service.impl;

import com.asen.commons.constants.BaseConstant;
import com.asen.commons.core.base.domain.Generic;
import com.asen.commons.core.base.result.BaseResultCode;
import com.asen.commons.core.base.service.GenericService;
import com.asen.commons.core.meta.dao.Condition;
import com.asen.commons.core.meta.entity.EntityObject;
import com.asen.commons.core.meta.entity.FieldObject;
import com.asen.commons.core.utils.EntityUtils;
import com.asen.commons.exception.IllegalLogicException;
import com.asen.commons.exception.ServiceException;
import com.asen.commons.utils.BaseAssert;
import com.asen.commons.utils.IdUtils;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 通用service抽象类
 *
 * @author Gary
 * @version 1.0
 * @date 2018-12-10
 */
@Slf4j
public class AbstractGenericServiceImpl<T extends Generic> extends AbstractCoreBaseServiceImpl<T> implements GenericService<T> {

    protected void initBaseInfo(T model) throws Exception {
        Date now = new Date();
        if (model.getCreateById() == null) {
            // TODO
            //model.setCreateById(currentUserId());
            model.setCreateById(0L);
            model.setCreateByName(null);
        }
        if (model.getCreateTime() == null) {
            model.setCreateTime(now);
        }
        if (model.getUpdateById() == null) {
            // TODO
            //model.setUpdateById(currentUserId());
            model.setUpdateById(0L);
            model.setUpdateByName(null);
        }
        if (model.getUpdateTime() == null) {
            model.setUpdateTime(now);
        }
    }

    @Override
    protected void beforeAdd(T model) throws Exception {
        super.beforeAdd(model);
        initBaseInfo(model);
    }

    @Override
    protected void updateValidate(T model) throws Exception {
        super.updateValidate(model);

        // 检查当前是否最新数据
        Condition condition = new Condition();
        condition.select("id", "updateTime");
        condition.equal("id", model.getId());
        T oldModel = this.getBy(condition);
        if (oldModel == null) {
            throw new ServiceException("单据不存在或已被删除！");
        }

        if (model.getUpdateTime() != null) {
            if (model.getUpdateTime().before(oldModel.getUpdateTime())) {
                throw new ServiceException(BaseResultCode.E0006);
            }
        }
    }

    @Override
    protected void beforeUpdate(T model) throws Exception {
        super.beforeUpdate(model);
        // TODO
        //model.setUpdateById(currentUserId());
        model.setUpdateById(0L);
        model.setUpdateTime(new Date());
        if (isGetOldModel(model) && IdUtils.isNotEmpty(model.getId())) {
            // 更新前将旧对象保存起来,待后续使用
            model.put(BaseConstant.OLD_MODEL, this.get(model.getId()));
        }
    }

    @Override
    protected void beforeRemove(T model) throws Exception {
        super.beforeRemove(model);
        // TODO
        //model.setUpdateById(currentUserId());
        model.setUpdateById(0L);
        model.setUpdateById(null);
        model.setUpdateTime(new Date());
    }

    private Object lock = new Object();

    @Override
    public void checkDupByFields(T model, String... fields) throws Exception {
        if (model == null || fields == null || fields.length == 0) {
            return;
        }
        Condition condition = new Condition();
        if (IdUtils.isNotEmpty(model.getId())) {
            condition.notEqual("id", model.getId());
        }
        List<String> msgList = new ArrayList<>();
        EntityObject entity = getEntity();
        for (String field : fields) {
            FieldObject fieldObject = entity.getFieldObject(field);
            if (fieldObject == null) {
                throw new IllegalLogicException("校验的字段在实体中不存在,请联系开发人员检查");
            }
            condition.equal(field, fieldObject.getValue(model));
            msgList.add(fieldObject.getAlias() + "【" + EntityUtils.getShowValue(model, fieldObject) + "】");
        }
        checkDupCondition(model, condition);

        int count = count(condition);
        BaseAssert.check(count == 0, msgList.stream().collect(Collectors.joining("，")) + "不能重复");
    }

    protected void checkDupCondition(T model, Condition condition) throws Exception {

    }

    /**
     * 是否在更新的时候先吧就记录保存下来
     * 子类自己重新判断,默认false
     *
     * @return
     */
    protected boolean isGetOldModel(T model) {
        return false;
    }


    /**
     * 获取分录key字段id对应的数值字段map (一般用于反写)
     *
     * @param entryList
     * @param oldEntryList
     * @param keyField
     * @param decimalField
     * @param isDeleted
     * @return
     * @throws Exception
     */
    //protected Map<Long, BigDecimal> getEntryDecimalMap(List<? extends GenericEntry> entryList, List<? extends GenericEntry> oldEntryList, String keyField, String decimalField, boolean isDeleted) throws Exception {
    //    Map<Long, BigDecimal> map = new HashMap<>();
    //    if (com.abel.utils.CollectionUtils.isNotEmpty(entryList)) {
    //        // 新分录有值
    //        EntityObject entityObject = EntityObjectLoader.getInstance().load(entryList.get(0).getClass());
    //        FieldObject keyFieldObject = entityObject.getFieldObject(keyField);
    //        FieldObject decimalFieldObject = entityObject.getFieldObject(decimalField);
    //        if (keyFieldObject == null || decimalFieldObject == null) {
    //            throw new IllegalLogicException("反写取数字段有误");
    //        }
    //        for (GenericEntry entry : entryList) {
    //            Long keyId = (Long) keyFieldObject.getValue(entry);
    //            BigDecimal decimalValue = (BigDecimal) decimalFieldObject.getValue(entry);
    //            map.put(keyId, DecimalUtils.add(map.get(keyId), DecimalUtils.negateIs(decimalValue, isDeleted)));
    //        }
    //    }
    //    if (!isDeleted && com.abel.utils.CollectionUtils.isNotEmpty(oldEntryList)) {
    //        // 非删除 且 旧分录不为空
    //        EntityObject entityObject = EntityObjectLoader.getInstance().load(oldEntryList.get(0).getClass());
    //        FieldObject keyFieldObject = entityObject.getFieldObject(keyField);
    //        FieldObject decimalFieldObject = entityObject.getFieldObject(decimalField);
    //        if (keyFieldObject == null || decimalFieldObject == null) {
    //            throw new IllegalLogicException("反写取数字段有误");
    //        }
    //        // 吧旧分录的数据都减掉
    //        for (GenericEntry entry : oldEntryList) {
    //            Long keyId = (Long) keyFieldObject.getValue(entry);
    //            BigDecimal decimalValue = (BigDecimal) decimalFieldObject.getValue(entry);
    //            map.put(keyId, DecimalUtils.subtract(map.get(keyId), decimalValue));
    //            if (DecimalUtils.equalZero(map.get(keyId))) {
    //                map.remove(keyId);
    //            }
    //        }
    //    }
    //    return map;
    //}

    /**
     * 获取分录key字段id对应的数值字段map (一般用于反写)
     *
     * @param model
     * @param entry
     * @param keyField
     * @param decimalField
     * @param isDeleted
     * @throws Exception
     */
    //protected Map<Long, BigDecimal> getEntryDecimalMap(T model, String entry, String keyField, String decimalField, boolean isDeleted) throws Exception {
    //    Map<Long, BigDecimal> map = new HashMap<>();
    //    if (model == null || StringUtils.isBlank(entry) || StringUtils.isBlank(keyField) || StringUtils.isBlank(decimalField)) {
    //        return map;
    //    }
    //    FieldObject entryFieldObject = getEntity().getFieldObject(entry);
    //    if (entryFieldObject == null) {
    //        throw new IllegalLogicException("对应分录属性不存在:" + entry);
    //    }
    //    List<? extends GenericEntry> entryList = (List<? extends GenericEntry>) entryFieldObject.getValue(model);
    //    T oldModel = (T) model.get(BaseConstant.OLD_MODEL);
    //    List<? extends GenericEntry> oldEntryList = null;
    //    if (oldModel != null) {
    //        oldEntryList = (List<? extends GenericEntry>) entryFieldObject.getValue(oldModel);
    //    }
    //    return getEntryDecimalMap(entryList, oldEntryList, keyField, decimalField, isDeleted);
    //}
}
